import json

import re

from django import http
from django.contrib.auth import login
from django.shortcuts import render, redirect

# Create your views here.
from django.urls import reverse
from django.views import View

from django.http.response import HttpResponseBadRequest, HttpResponse, JsonResponse
from django_redis import get_redis_connection

from apps.carts.utils import merge_cookie_to_redis
from apps.goods.models import SKU
from apps.users.models import User, Address
from apps.users.utils import generic_active_email_url, check_active_token
from utils.response_code import RETCODE
from utils.users import logger


class RegisterView(View):
    '''这里是用户注册'''
    def get(self,request):
        # 提供注册页面
        # ：param request: 请求对象
        # :return: 注册界面
        return render(request,"register.html")

    # ① 接收数据
    def post(self,request):
        username = request.POST.get("username")
        password = request.POST.get("password")
        password2 = request.POST.get("password2")
        mobile = request.POST.get("mobile")

        # ② 验证数据 (我们不相信前端提交的任何数据)
        # 2.1四个参数都必须有值
        if not all([username,password,password2,mobile]):
            # 说明有变量为空值
            return HttpResponseBadRequest("参数不全")

        # 2.2判断用户名是否符合规则
        import re
        if not re.match(r"[a-zA-z0-9]{5,20}",username):
            return HttpResponseBadRequest("用户名不满足条件")
                # 判断用户名是否重复
        # 2.3密码是否符合规则
        if not re.match(r"[a-zA-Z0-9]{8,20}",password):
            return HttpResponseBadRequest("密码不符合规则")

        # 2.4确认密码一致
        if password2 != password:
            return HttpResponseBadRequest("密码不一致")

        # 2.5判断手机号是否符合规则
        if not re.match(r"^1[3-9]\d{9}$",mobile):
            return HttpResponseBadRequest("手机号错误")
                # 判断手机号是否重复

        # ③ 保存数据
        user = User.objects.create_user(username=username,
                                       password=password,
                                       mobile=mobile)

        # 设置session
        # request.session['username'] = user.username
        # request.session['id'] = user.id

        # admin 在登陆时可以帮助我们记录登陆状态
        from django.contrib.auth import login
        # request
        # user 用户对象
        login(request,user)


        # ④ 返回相应
        return redirect(reverse("contents:index"))

        return HttpResponse("ok")


class RegisterUsernameCountView(View):

    def get(self,request,username):
        # 1.查询前端提交的数据
        # 2.查询数量
        count = User.objects.filter(username=username).count()
        # 数量1： 重复
        # 数量2： 不重复
        return JsonResponse({"count":count})



class LoginView(View):

    def get(self,request):

        return render(request,"login.html")


    # 405 Method Not Allowed     没有实现对应的请求方法
    def post(self,request):

        # 1 接收数据
        username = request.POST.get("username")
        password = request.POST.get("pwd")
        remembered = request.POST.get("remembered")
         # ​
        # 2 验证数据(参数是否齐全, 是否符合规则)
        if not all([username,password]):
            return HttpResponseBadRequest("参数不全")

        # 用户名密码是否符合规则此处省略
        # 3 在判断用户名密码是否匹配
        from django.contrib.auth import authenticate
        # 认证成功返回user对象，失败则返回None
        from django.contrib.auth.backends import ModelBackend
        user = authenticate(request,username=username,password=password)
        if user is None:
            return HttpResponseBadRequest("用户名或密码错误")


         # ​
        # 4 状态保持
        login(request,user)

     # ​
        # 5 记住登陆
        if remembered == "on":
            # 记住登陆
            request.session.set_expiry(None)
        else:
            # 不记住登陆
            request.session.set_expiry(0)
         # ​
        # 6 返回响应

        response = redirect(reverse("contents:index"))
        # 设置cookie
        response.set_cookie("username",user.username,max_age=3600*24*14)
        response = merge_cookie_to_redis(request=request,user=user,response=response)

        return response

# 请求方式 GET  logout
class LogoutView(View):
    def get(self,request):
        # request.session.flush()
        from django.contrib.auth import logout
        logout(request)

        # 删除cookie中的username

        response = redirect(reverse("contents:index"))

        # response.set_cookie("username",None,max_age=0)
        response.delete_cookie("username")

        return response

'''
登录用户才可以访问个人中心


1.页面必须是登陆用户才可以访问
2.可以用已知学的知识来实现判断
3.使用系统的mixin
4.修改了mixin的默认跳转url

'''
from django.contrib.auth.mixins import LoginRequiredMixin
class UserCenterInfoView(LoginRequiredMixin,View):

    def get(self,request):
        # request.user 请求中有用户的信息
        # is_authenticated  判断用户是否为登录状态
        # 登录用户为 True
        #  未登录用户为 False

        # if requ        est.user.is_authenticated:
        #     return render(request,"user_center_info.html")
        # else:
        #     return redirect(reverse("users:login"))


        # 1.获取/组织登陆用户的信息
        context = {
            "username":request.user.username,
            "mobile": request.user.mobile,
            "email": request.user.email,
            "email_active": request.user.email_active,
        }

        # 2.传递给模板,让模板进行渲染

        return render(request,"user_center_info.html",context=context)

"""
1.功能分析
    用户行为:       用户输入邮箱之后,点击保存
    前端行为:       邮箱提交给后端
    后端行为:       保存邮箱,给这个邮箱发送一个激活连接,


2. 分析后端实现的大体步骤
        !!!必须是登陆用户才可以访问!!!
        ① 接收
        ② 验证
        ③ 更新数据
        ④ 给邮箱发送激活连接
        ⑤ 返回相应

3.确定请求方式和路由

    put/post/get

    GET     --获取数据
    POST    --新增数据
    PUT     --更新数据
    DELETE  --删除数据

    put   put和post类似,请求的数据在body中
    发送axios 请求,传递是 JSON数据


"""

class EmailView(LoginRequiredMixin,View):

    def put(self,request):
        # !!!必须是登陆用户才可以访问!!!
        # ① 接收    axios
        body = request.body
        body_str = body.decode()
        data = json.loads(body_str)

        # ② 验证
        email = data.get("email")
        if not re.match(r"^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$",email):
            # PARAMERR  参数错误
            return JsonResponse({"code":RETCODE.PARAMERR,"errmsg":"邮箱不符合规则"})
        # ③ 更新数据
        request.user.email = email
        request.user.save()
        # ④ 给邮箱发送激活连接

        from django.core.mail import send_mail
        # # subject     主题
        # subject = "I Love You"
        # message = "xxxxxxxxxx"           #内容
        # from_email = "欢乐玩家<shi_xin_ya@163.com>"   #谁发的
        # recipient_list = ["shi_xin_ya@163.com"]  #收件人,列表
        #
        #
        # # 对用户信息进行加密
        #
        # active_url = generic_active_email_url(request.user.id,email)
        # # 用户点击这个连接让他跳转到指定页面,同时修改这个用户的邮件状态
        # html_mesage = "<a href='%s'>点点点</a>"%active_url
        #
        # send_mail(subject=subject,
        #           message=message,
        #           from_email=from_email,
        #           recipient_list=recipient_list,
        #           html_message=html_mesage)
        from celery_tasks.email.tasks import send_active_email
        send_active_email.delay(request.user.id,email)


        # ⑤ 返回相应
        return JsonResponse({"code":RETCODE.OK,"errmsg":"ok"})



# Day  5开始

from django.db import DataError
class EmaileActiveView(View):

    def get(self,request):
        # 1.获取token信息
        token = request.GET.get("token")
        if token is None:
            return HttpResponseBadRequest("缺少参数")
        # 2.token信息解密
        data = check_active_token(token)
        if data is None:
            return HttpResponseBadRequest("验证失败")
        # 3.根据用户信息进行数据的更新
        id = data.get("id")
        email = data.get("email")

        # 查询指定用户,request.user 可能没登陆用户信息
        try:
            user = User.objects.get(id=id,email=email)
        except User.DoesNotExist:
            return HttpResponseBadRequest("验证失败")
        user.email_active = True
        user.save()


        # 4,跳转到指定页面
        return redirect(reverse("users:center"))

        # return HttpResponse("激活成功")
        # return render(request)


class UserCenterSiteView(View):
    def get(self,request):
        return render(request,"user_center_site.html")



"""

新增地址

1.功能分析
    用户行为:       填写完成地址信息
    前端行为:       收集相关信息
    后端行为:       保存入库

2. 分析后端实现的大体步骤
        ① 接收数据
        ② 验证数据
        ③ 数据入库
        ④ 返回相应

3.确定请求方式和路由
    POST        /addresses/create/

"""
# class CreateAddressView(LoginRequiredMixin, View):
#     """新增地址"""
#
#     def post(self, request):
#         """实现新增地址逻辑"""
#         # 判断是否超过地址上限：最多20个
#         # Address.objects.filter(user=request.user).count()
#         count = request.user.addresses.count()
#         if count >= 20:
#             return JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'})
#
#         # 接收参数
#         json_dict = json.loads(request.body.decode())
#         receiver = json_dict.get('receiver')
#         province_id = json_dict.get('province_id')
#         city_id = json_dict.get('city_id')
#         district_id = json_dict.get('district_id')
#         place = json_dict.get('place')
#         mobile = json_dict.get('mobile')
#         tel = json_dict.get('tel')
#         email = json_dict.get('email')
#
#         # 校验参数
#         if not all([receiver, province_id, city_id, district_id, place, mobile]):
#             return HttpResponseBadRequest('缺少必传参数')
#         if not re.match(r'^1[3-9]\d{9}$', mobile):
#             return HttpResponseBadRequest('参数mobile有误')
#         if tel:
#             if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
#                 return HttpResponseBadRequest('参数tel有误')
#         if email:
#             if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
#                 return HttpResponseBadRequest('参数email有误')
#
#         # 保存地址信息
#         try:
#             address = Address.objects.create(
#                 user=request.user,
#                 title = receiver,
#                 receiver = receiver,
#                 province_id = province_id,
#                 city_id = city_id,
#                 district_id = district_id,
#                 place = place,
#                 mobile = mobile,
#                 tel = tel,
#                 email = email
#             )
#
#             # 设置默认地址
#             if not request.user.default_address:
#                 request.user.default_address = address
#                 request.user.save()
#         except Exception as e:
#             logger.error(e)
#             return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '新增地址失败'})
#
#         # 新增地址成功，将新增的地址响应给前端实现局部刷新
#         address_dict = {
#             "id": address.id,
#             "title": address.title,
#             "receiver": address.receiver,
#             "province": address.province.name,
#             "city": address.city.name,
#             "district": address.district.name,
#             "place": address.place,
#             "mobile": address.mobile,
#             "tel": address.tel,
#             "email": address.email
#         }
#
#         # 响应保存结果
#         return JsonResponse({'code': RETCODE.OK, 'errmsg': '新增地址成功', 'address':address_dict})
#
#
#
# """
class CreateAddressView(LoginRequiredMixin, View):
    """新增地址"""

    # def post(self, request):
    #     """实现新增地址逻辑"""
    #     # 判断是否超过地址上限：最多20个
    #     # Address.objects.filter(user=request.user).count()
    #     count = request.user.addresses.count()
    #     if count >= 20:
    #         return JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'})
    #
    #     # 接收参数
    #     json_dict = json.loads(request.body.decode())
    #     receiver = json_dict.get('receiver')
    #     province_id = json_dictForeignKey('areas.Area', on_delete=models.PROTECT, related_name='city_addresses', verbose_name='市')
    #     city_id = json_dict.get('city_id')
    #     district_id = json_dict.get('district_id')
    #     place = json_dict.get('place')
    #     mobile = json_dict.get('mobile')
    #     tel = json_dict.get('tel')
    #     email = json_dict.get('email')
    #
    #     # 校验参数
    #     if not all([receiver, province_id, city_id, district_id, place, mobile]):
    #         return HttpResponseBadRequest('缺少必传参数')
    #     if not re.match(r'^1[3-9]\d{9}$', mobile):
    #         return HttpResponseBadRequest('参数mobile有误')
    #     if tel:
    #         if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
    #             return HttpResponseBadRequest('参数tel有误')
    #     if email:
    #         if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
    #             return HttpResponseBadRequest('参数email有误')
    #
    #     # 保存地址信息
    #     try:
    #         address = Address.objects.create(
    #             user=request.user,
    #             title = receiver,
    #             receiver = receiver,
    #             province_id = province_id,
    #             city_id = city_id,
    #             district_id = district_id,
    #             place = place,
    #             mobile = mobile,
    #             tel = tel,
    #             email = email
    #         )
    #
    #         # 设置默认地址
    #         if not request.user.default_address:
    #             request.user.default_address = address
    #             request.user.save()
    #     except Exception as e:
    #             logger.error(e)
    #             return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '新增地址失败'})
    #
    #     # 新增地址成功，将新增的地址响应给前端实现局部刷新
    #     address_dict = {
    #         "id": address.id,
    #         "title": address.title,
    #         "receiver": address.receiver,
    #         "province": address.province.name,
    #         "city": address.city.name,
    #         "district": address.district.name,
    #         "place": address.place,
    #         "mobile": address.mobile,
    #         "tel": address.tel,
    #         "email": address.email
    #     }
    #
    #     # 响应保存结果
    #     return JsonResponse({'code': RETCODE.OK, 'errmsg': '新增地址成功', 'address':address_dict})





    def post(self, request):
        """实现新增地址逻辑"""
        # 判断是否超过地址上限：最多20个
        # Address.objects.filter(user=request.user).count()
        count = request.user.addresses.count()
        if count >= 50:
            return JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'})

        # 接收参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return HttpResponseBadRequest('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return HttpResponseBadRequest('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return HttpResponseBadRequest('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return HttpResponseBadRequest('参数email有误')

        # 保存地址信息
        try:
            address = Address.objects.create(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )

            # 设置默认地址
            if not request.user.default_address:
                request.user.default_address = address
                request.user.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '新增地址失败'})

            # 新增地址成功，将新增的地址响应给前端实现局部刷新
# 删除地址
#
# 1.功能分析
#     用户行为:       点击想要删除的某一个地址
#     前端行为:       传递一个删除id
#     后端行为:       实现删除
#
# 2. 分析后端实现的大体步骤
#         ① 接收参数
#         ② 验证参数
#         ③ 实现删除
#         ④ 返回相应
#
# 3.确定请求方式和路由
#     DELETE  addresses/(?P<address_id>\d+)/
# """
#
# """
#
# 修改地址
#
# 1.功能分析
#     用户行为:     点击编辑某一个
#     前端行为:     收集更新的数据
#     后端行为:       实现更新
#
# 2. 分析后端实现的大体步骤
#
#             ① 接收数据
#             ② 验证数据
#             ③ 查询并更新数据
#             ④ 返回相应
#
# 3.确定请求方式和路由
#     PUT     addresses/(?P<address_id>\d+)/
#
# """
#
# """
#
# 查询地址
#
# 1.功能分析
#     用户行为:   刷新页面
#     前端行为:   传递用户信息 (session 是依赖于cookie,cookie信息肯定是传递给后端)
#     后端行为:   根据用户信息,查询指定用户的地址
#
# 2. 分析后端实现的大体步骤
#         ① 获取登陆用户信息
#         ② 根据用户信息进行查询
#         ③ 将对象列表转换为字典列表
#         ④ 返回相应
#
# 3.确定请求方式和路由
#     GET     addresses/
# """





###################用户浏览记录###################

class UserHistoryView(LoginRequiredMixin,View):
    def post(self,request):
        # 1.用户信息
        user = request.user
        # 2.获取商品id
        data = json.loads(request.body.decode())
        sku_id = data.get("sku_id")
        # 3.判断商品id
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({"code":RETCODE.NODATAERR,"errmsg":"没有此商品"})
        # 4.数据保存
        redis_conn = get_redis_connection("history")
        # 一.创建管道实例
        pipeline=redis_conn.pipeline()

        # 二,管道收集指令
        # 4.1先去重
        pipeline.lrem("history_%s"%user.id,0,sku_id)
        # 4.2在添加
        pipeline.lpush("history_%s"%user.id,sku_id)
        # 4.3保留5条数据
        pipeline.ltrim("history_%s"%user.id,0,4)

        # 三,执行,一定要记得执行
        pipeline.execute()

        # # 4.1先去重
        # redis_conn.lrem("history_%s"%user.id,0,sku_id)
        # # 4.2在添加
        # redis_conn.lpush("history_%s"%user.id,sku_id)
        # # 4.3保留5条数据
        # redis_conn.ltrim("history_%s"%user.id,0,4)
        # 5.返回响应
        return JsonResponse({"code":RETCODE.OK,"errmsg":"ok"})

    def get(self,request):
        # 1.获取用户信息
        user=request.user
        # 2.获取redis数据
        redis_conn = get_redis_connection("history")
        ids=redis_conn.lrange("history_%s"%user.id,0,4)

        history_list=[]
        for id in ids:
            # 3.根据id查询商品详细信息 SKU
            sku = SKU.objects.get(id=id)
            # ​4.将对象转换为字典
            history_list.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })
        # 5.返回数据

        return JsonResponse({"code":RETCODE.OK,"errmsg":"ok","skus":history_list})

















